package com.yuanxin.baidumap;

import android.app.SearchManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.location.Geocoder;
import android.util.Log;

import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.model.LatLngBounds;
import com.baidu.mapapi.search.core.PoiInfo;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.geocode.GeoCodeOption;
import com.baidu.mapapi.search.geocode.GeoCodeResult;
import com.baidu.mapapi.search.geocode.GeoCoder;
import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeOption;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
import com.baidu.mapapi.search.poi.OnGetPoiSearchResultListener;
import com.baidu.mapapi.search.poi.PoiBoundSearchOption;
import com.baidu.mapapi.search.poi.PoiCitySearchOption;
import com.baidu.mapapi.search.poi.PoiDetailResult;
import com.baidu.mapapi.search.poi.PoiIndoorResult;
import com.baidu.mapapi.search.poi.PoiNearbySearchOption;
import com.baidu.mapapi.search.poi.PoiResult;
import com.baidu.mapapi.search.poi.PoiSearch;
import com.baidu.mapapi.search.poi.PoiSortType;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.RCTNativeAppEventEmitter;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * 百度地图搜索功能
 * 郭凯
 */
public class ReactMapSearchModule extends ReactContextBaseJavaModule {

    private final static String TAG = "ReactMapSearchModule";

    private int pageNum = 0;
    private int pageSize = 20;
    private int radius = 1000;

    GeoCoder geoCoder;


    PoiSearch mPoiSearch;


    class GetGeoCoderResult implements OnGetGeoCoderResultListener {

        //唯一编码
        private String uuid;

        public void setUuid(String uuid) {
            this.uuid = uuid;
        }

        public String getUuid() {
            return uuid;
        }

        public GetGeoCoderResult(String uuid){
            this.uuid = uuid;
        }

        @Override
        public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
            if (geoCodeResult != null) {
                Promise promise = promiseMap.get(uuid);
                if(promise==null)
                    return;
                promiseMap.remove(uuid);
                LatLng location = geoCodeResult.getLocation();
                String address = geoCodeResult.getAddress();
                // Log.e(TAG, "onGetGeoCodeResult: " + "location-" + location
//                        + "-address-" + address);
                if (location != null && address != null) {
                    double longitude = location.longitude;
                    double latitude = location.latitude;
                    WritableMap writablelat = Arguments.createMap();
                    writablelat.putDouble("longitude", longitude);
                    writablelat.putDouble("latitude", latitude);

                    WritableMap writableMap = Arguments.createMap();
                    writableMap.putString("address", address);
                    writableMap.putMap("location", writablelat);
                    promise.resolve(writableMap);
                } else {
                    promise.reject("error:", "没有找到检索结果");
                }

            }
            if(geoCoder!=null){
                try {
                    geoCoder.destroy();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onGetReverseGeoCodeResult(ReverseGeoCodeResult GeoCodeResult) {
            if (GeoCodeResult != null) {
                Promise promise = promiseMap.get(uuid);
                if(promise==null)
                    return;
                promiseMap.remove(uuid);

                WritableMap writablemap = Arguments.createMap();

                if (GeoCodeResult.getAddress() != null && GeoCodeResult.getLocation() != null) {

                    String address = GeoCodeResult.getAddress();

                    ReverseGeoCodeResult.AddressComponent addressdetail = GeoCodeResult.getAddressDetail();
                    String streetNumber = addressdetail.streetNumber;
                    String street = addressdetail.street;
                    String district = addressdetail.district;
                    String city = addressdetail.city;
                    String province = addressdetail.province;
                    WritableMap mapaddressdetail = Arguments.createMap();
                    mapaddressdetail.putString("streetNumber", streetNumber);
                    mapaddressdetail.putString("street", street);
                    mapaddressdetail.putString("district", district);
                    mapaddressdetail.putString("city", city);
                    mapaddressdetail.putString("province", province);

                    LatLng latLng = GeoCodeResult.getLocation();
                    double longitude = latLng.longitude;
                    double latitude = latLng.latitude;
                    WritableMap maplatlng = Arguments.createMap();
                    maplatlng.putDouble("longitude", longitude);
                    maplatlng.putDouble("latitude", latitude);

                    writablemap.putString("address", address);
                    writablemap.putMap("addressDetail", mapaddressdetail);
                    writablemap.putMap("location", maplatlng);

                    promise.resolve(writablemap);
                } else {
                    promise.reject("error:", "没有找到检索结果");
                }

            }
            if(geoCoder!=null){
                try {
                    geoCoder.destroy();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class PoiSearchResult implements OnGetPoiSearchResultListener {


        //唯一编码
        private String uuid;

        public void setUuid(String uuid) {
            this.uuid = uuid;
        }

        public String getUuid() {
            return uuid;
        }
        public PoiSearchResult(String uuid){
            this.uuid = uuid;
        }
        @Override
        public void onGetPoiResult(PoiResult poiResult) {
            Promise promise = promiseMap.get(uuid);
            if(promise==null)
                return;
            promiseMap.remove(uuid);
            if (poiResult == null || poiResult.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {
                promise.reject("error:", "没有找到检索结果");
            }
            if (poiResult.error == SearchResult.ERRORNO.NO_ERROR) {
                List<PoiInfo> poilist = poiResult.getAllPoi();
                WritableArray polArr = Arguments.createArray();
                for (int i = 0; i < poilist.size(); i++) {
                    PoiInfo pi = poilist.get(i);
                    String name = pi.name;
                    String address = pi.address;
                    WritableMap map = Arguments.createMap();
                    map.putString("name", name);
                    map.putString("address", address);
//                    map.putString("poiType", pi.type.name());
                    map.putInt("poiType",  pi.type.ordinal());
                    if (pi.location != null) {
                        map.putDouble("latitude", pi.location.latitude);
                        map.putDouble("longitude", pi.location.longitude);
                    }
                    polArr.pushMap(map);

                }
                promise.resolve(polArr);
//            getReactApplicationContext()
//                    .getJSModule(RCTNativeAppEventEmitter.class)
//                    .emit("MapSearch_Resp", polArr);
            }
            if(mPoiSearch!=null){
                mPoiSearch.destroy();
            }
        }

        @Override
        public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {

        }

        @Override
        public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {

        }
    }



    Map<String, Promise> promiseMap ;

    @Override
    public String getName() {
        return "MapSearchService";
    }

    public ReactMapSearchModule(final ReactApplicationContext reactContext) {
        super(reactContext);
        promiseMap = new HashMap();
//        SDKInitializer.initialize(reactContext.getApplicationContext());
    }

    /**
     * 根据地理位置经玮度获取地方名称
     */
    @ReactMethod
    public void reverseGeoCode(ReadableMap map, Promise promise) {
        // Log.e(TAG, "reverseGeoCode---" + map);

        geoCoder = GeoCoder.newInstance();
        Double latitude = map.getDouble("latitude");
        Double longitude = map.getDouble("longitude");
        // Log.e(TAG, "latitude---" + latitude + "---longitude---" + longitude);
        LatLng latLng = new LatLng(latitude, longitude);
        ReverseGeoCodeOption option = new ReverseGeoCodeOption().location(latLng);
        GetGeoCoderResult getGeoCoderResult = new GetGeoCoderResult(UUID.randomUUID().toString());
        geoCoder.setOnGetGeoCodeResultListener(getGeoCoderResult);
        geoCoder.reverseGeoCode(option);
        promiseMap.put(getGeoCoderResult.getUuid(), promise);
    }

    /**
     * 根据地址名称获地理位置经玮度
     */
    @ReactMethod
    public void geoCode(ReadableMap map, Promise promise) {
        // Log.e(TAG, "geoCode---" + map);

        geoCoder = GeoCoder.newInstance();
        String city = map.getString("city");
        String address = map.getString("address");
        // Log.e(TAG, "city---" + city + "---address---" + address);
        GeoCodeOption option = new GeoCodeOption().city(city).address(address);
        GetGeoCoderResult getGeoCoderResult = new GetGeoCoderResult(UUID.randomUUID().toString());
        geoCoder.setOnGetGeoCodeResultListener(getGeoCoderResult);
        geoCoder.geocode(option);
        promiseMap.put(getGeoCoderResult.getUuid(), promise);
    }

    /**
     * 城市POI检索(关键词)
     */
    @ReactMethod
    public void poiSearchInCity(ReadableMap options, Promise promise) {
        // Log.e(TAG, "poiSearchInCity---" + options);
        PoiSearchResult poiSearchResult = new PoiSearchResult(UUID.randomUUID().toString());
        // 初始化搜索对象
        mPoiSearch = PoiSearch.newInstance();
        mPoiSearch.setOnGetPoiSearchResultListener(poiSearchResult);
        String keystr = options.getString("keyword");
        String citystr = options.getString("city");
        pageNum = options.hasKey("page") ? options.getInt("page") : pageNum;
        pageSize = options.hasKey("pageSize") ? options.getInt("pageSize") : pageSize;
        boolean flag = mPoiSearch.searchInCity((new PoiCitySearchOption())
                .city(citystr).keyword(keystr).pageNum(pageNum).pageCapacity(pageSize));
        promiseMap.put(poiSearchResult.getUuid(), promise);
    }

    /**
     * 根据范围和检索词发起范围检索
     */
    @ReactMethod
    public void poiSearchInbounds(ReadableMap map, Promise promise) {
        // Log.e(TAG, "poiSearchInbounds---" + map);
        mPoiSearch = PoiSearch.newInstance();
        PoiSearchResult poiSearchResult = new PoiSearchResult(UUID.randomUUID().toString());
        mPoiSearch.setOnGetPoiSearchResultListener(poiSearchResult);
        PoiBoundSearchOption boundSearchOption = new PoiBoundSearchOption();
        ReadableMap leftBottom = map.getMap("leftBottom");
        ReadableMap rightTop = map.getMap("rightTop");
        String keywords = map.getString("keyword");
        int pageIndex = map.hasKey("pageIndex") ? map.getInt("pageIndex") : 0;
        int pageCapacity = map.hasKey("pageCapacity") ? map.getInt("pageCapacity") : 10;
        LatLng southwest = new LatLng(leftBottom.getDouble("latitude"), leftBottom.getDouble("longitude"));// 西南
        LatLng northeast = new LatLng(rightTop.getDouble("latitude"), rightTop.getDouble("longitude"));// 东北
        LatLngBounds bounds = new LatLngBounds.Builder().include(southwest)
                .include(northeast).build();// 得到一个地理范围对象
        boundSearchOption.bound(bounds);// 设置poi检索范围
        boundSearchOption.keyword(keywords);// 检索关键字
        boundSearchOption.pageNum(pageIndex);
        boundSearchOption.pageCapacity(pageCapacity);
        boolean flag = mPoiSearch.searchInBound(boundSearchOption);// 发起poi范围检索请求
        promiseMap.put(poiSearchResult.getUuid(), promise);
    }

    /**
     * 根据中心点、半径和检索词发起周边检索
     */
    @ReactMethod
    public void poiSearchNearBy(ReadableMap options, Promise promise) {
        // Log.e(TAG, "poiSearchNearBy---" + options);
        mPoiSearch = PoiSearch.newInstance();
        PoiSearchResult poiSearchResult = new PoiSearchResult(UUID.randomUUID().toString());
        mPoiSearch.setOnGetPoiSearchResultListener(poiSearchResult);
        String keystr = options.getString("keyword");
        pageNum = options.hasKey("page") ? options.getInt("page") : pageNum;
        pageSize = options.hasKey("pageSize") ? options.getInt("pageSize") : pageSize;
        ReadableMap location = options.getMap("location");
        double latitude = location.getDouble("latitude");
        double longitude = location.getDouble("longitude");
        int radius = options.getInt("radius");
        PoiNearbySearchOption nearbySearchOption = new PoiNearbySearchOption().keyword(keystr
                .toString()).sortType(PoiSortType.distance_from_near_to_far).location(new LatLng(latitude, longitude))
                .radius(radius).pageNum(pageNum).pageCapacity(pageSize);
        boolean flag = mPoiSearch.searchNearby(nearbySearchOption);
        promiseMap.put(poiSearchResult.getUuid(), promise);
    }

    /**
     * 根据中心点、半径和关键字（key1$key2$key3......）发起周边检索
     *
     * @param options
     * @param promise
     */
    @ReactMethod
    public void poiSearchNearByMoreKey(ReadableMap options, Promise promise) {
        // Log.e(TAG, "poiSearchNearBy---" + options);
        mPoiSearch = PoiSearch.newInstance();
        PoiSearchResult poiSearchResult = new PoiSearchResult(UUID.randomUUID().toString());
        mPoiSearch.setOnGetPoiSearchResultListener(poiSearchResult);
        String keystr = options.getString("keyword");
        pageNum = options.hasKey("page") ? options.getInt("page") : pageNum;
        pageSize = options.hasKey("pageSize") ? options.getInt("pageSize") : pageSize;
        ReadableMap location = options.getMap("location");
        double latitude = location.getDouble("latitude");
        double longitude = location.getDouble("longitude");
        int radius = options.getInt("radius");
        String ak = "";
        ApplicationInfo appInfo = null;
        try {
            appInfo = getReactApplicationContext().getPackageManager()
                    .getApplicationInfo(getReactApplicationContext().getPackageName(),
                            PackageManager.GET_META_DATA);
            ak = appInfo.metaData.getString("com.baidu.lbsapi.API_KEY");
        } catch (Exception e) {
            e.printStackTrace();
        }
        String url = "http://api.map.baidu.com/place/v2/search?query=" + keystr + "&location=" +
                latitude + "," + longitude + "&radius=" + radius + "&output=json&ak=" + ak + "&page_num=" + pageNum + "&page_size=" + pageSize + "&scope=2&filter=sort_name:distance|sort_rule:1";
        // Log.i(TAG, "url===>" + url);

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().get().url(url).build();

        client.newCall(request).enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // Log.i(TAG, "e===>" + e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                // Log.i(TAG, "Response===>" + response.body().string());
            }
        });


    }

    private static WritableMap flagToMap(int code, String msg) {
        WritableMap map = Arguments.createMap();
        map.putInt("returnCode", code);
        map.putString("returnMsg", msg);
        return map;
    }

}
